package hu.elte.inf.holiuml.gui;

import hu.elte.inf.holiuml.model.Operation;
import hu.elte.inf.holiuml.model.Var;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;

public class ClassOperationOptionsDialog extends OptionsDialog{
	
	private JPanel propPanel;
	private JPanel editPanel;
	JTable table;
	String operatorParameters;
	boolean parametersOk = true;
	TableModel tableModel;
	Vector<Operation> operations = new Vector<Operation>();
	Vector<String> parameters = new Vector<String>();
	public ClassOperationOptionsDialog(HoliUML parent, String title, Vector<Operation> operations) {
		super(parent, title);
		if(operations != null){
			for(int i= 0; i < operations.size(); i++){
				this.operations.add(new Operation(operations.get(i)));
				parameters.add(parametersToString(operations.get(i).getParameters()));
			}
		}
		createPropPanel();
		fillPanels();
		setSize(new Dimension(700,280));
		setModalityType(ModalityType.APPLICATION_MODAL);
		setVisible(true);
	}
		
	private void createPropPanel(){
		propPanel = new JPanel(new BorderLayout());
		createTableModel();
		table = new JTable(tableModel, new ClassOperationsTableColumns());
		table.setPreferredSize(new Dimension(400,150));
		JComboBox visibilityCombo = new JComboBox((new Operation()).getVisibilities());
		visibilityCombo.setSelectedIndex(0);
		table.getColumn("Visibility").setCellEditor(new DefaultCellEditor(visibilityCombo));
		JComboBox returnValueCombo = new JComboBox((new Var()).getTypes());
		returnValueCombo.setSelectedIndex(0);
		JComboBox returnTypeModifierCombo = new JComboBox((new Var()).getTypeModifiers());
		returnValueCombo.setSelectedIndex(0);
		table.getColumn("Return Type").setCellEditor(new DefaultCellEditor(returnValueCombo));
		table.getColumn("Type Modifier").setCellEditor(new DefaultCellEditor(returnTypeModifierCombo));
		table.getColumn("Name").setCellEditor(new DefaultCellEditor(new JTextField()));
		JTextField parameters = new JTextField();
		parameters.setToolTipText("Example: int firstParameter; boolean secondParameter");
		table.getColumn("Parameters").setCellEditor(new DefaultCellEditor(parameters));
		table.getColumn("Description").setCellEditor(new DefaultCellEditor(new JTextField()));
		(table.getTableHeader()).setReorderingAllowed(false);
		JScrollPane scrollPane = new JScrollPane(table);
		scrollPane.setPreferredSize(new Dimension(400,150));
		JButton addButton = new JButton("Add New");
		addButton.addActionListener(addOperationAction);
		JButton deleteButton = new JButton("Delete Selected");
		deleteButton.addActionListener(deleteOperationAction);
		editPanel = new JPanel(new GridLayout(1,2));
		editPanel.add(addButton);
		editPanel.add(deleteButton);
		JButton help = new JButton("Help");
		help.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Vector<String> varTypes = (new Var()).getTypes();
				JOptionPane.showMessageDialog(parent, "Legal value for parameters is for example: Type1 Name1; Type2 Name2\n" +
						"Legal values for type are: " + varTypes);
		}});
		propPanel.add("North", help);
		propPanel.add("Center", scrollPane);
		propPanel.add("South", editPanel);

	}
	
	private void fillPanels(){
		getContentPane().setLayout(new BorderLayout());
		getContentPane().add("North", propPanel);
		getContentPane().add("South", buttonPanel);
	}
	
	protected void createTableModel(){
		tableModel = new AbstractTableModel(){
	          public int getColumnCount() { return 6; }
	          public int getRowCount() { return operations.size();}
	          public boolean isCellEditable(int col, int row){
	        	  return true;
	          }
	          // visibility, return value, type modifier, name, parameters, description
	          public Object getValueAt(int row, int col) {
	        	  Operation operation = operations.get(row); 
	        	  switch(col){
	        	  	case 0 : return operation.getVisibility();
	        	  	case 1 : return operation.getReturnData().getType();
	        	  	case 2 : return operation.getReturnData().getTypeModifyer();
	        	  	case 3 : return operation.getName();
	        	  	case 4 : return parameters.get(row);
	        	  	case 5 : return operation.getDescription();
	        	  }
	        	  return null;
	          }
	          public void setValueAt(Object value, int row, int col) {
	        	  Operation operation = operations.get(row);
	        	  switch(col){
	        	  	case 0 : operation.setVisibility(Operation.Visibility.valueOf(value.toString()));break;
	        	  	case 1 : operation.getReturnData().setType(Var.VarType.valueOf(value.toString()));break;
	        	  	case 2 : operation.getReturnData().setTypeModifyer(Var.TypeModifyer.valueOf(value.toString()));break;
	        	  	case 3 : operation.setName((String)value);break;
	        	  	case 4 : parameters.set(row, value.toString());
	        	  			 parseParameters(value.toString());
	        	  			 break;
	        	  	case 5 : operation.setDescription((String)value);break;
	        	  	default : break;
	        	  }
	        	  fireTableDataChanged();
	          }
		};
	}
	
	private String parametersToString(Vector<Var> vector){
		String line = new String();
		for(int i = 0; i < vector.size(); i++){
			line += vector.get(i).getType().toString();
			if(vector.get(i).getTypeModifyer() == Var.TypeModifyer.ARRAY){
				line += "[]";
			}
			line += " " + vector.get(i).getName().toString() + ";";
		}
		return line;
	}
	
	private Vector<Var> parseParameters(String op){
		String[] strings = op.trim().split(";");
		Vector<Var> parameters = new Vector<Var>();
		if(!op.trim().equals("")){
			for(int i = 0; i < strings.length; i++){
				String[] param = strings[i].trim().split(" ",2);
				if(param.length == 2 && isLegalAttribute(param[1])){
					boolean typeModifier = false;
					if(param[0].endsWith("[]")){
						typeModifier = true;
						param[0] = param[0].substring(0, param[0].length() - 2);
					}
					if(isLegalType(param[0].toUpperCase())){
						Var var = new Var();
						var.setType(Var.VarType.valueOf(param[0].toUpperCase()));
						var.setName(param[1].trim());
						if(typeModifier){
							var.setTypeModifyer(Var.TypeModifyer.ARRAY);
						}
						parameters.add(var);
					}else{
						JOptionPane.showMessageDialog(parent, "The ''" + param[0] + "'' type is illegal!", "Error!", JOptionPane.ERROR_MESSAGE);
						return null;
					}
				}else{
					JOptionPane.showMessageDialog(parent, "Separator ''; '' missing!", "Error!", JOptionPane.ERROR_MESSAGE);
					return null;
				}
			}
		}
		return parameters;
	}
	
	private boolean isLegalAttribute(String string){
		if(string.trim().split(" ").length == 1){
			return true;
		}
		return false;
	}
	
	private boolean isLegalType(String string){
		Vector<String> types = (new Var()).getTypes();
		for(int i = 0; i < types.size(); i++){
			if(types.get(i).equals(string)){
				return true;
			}
		}
		return false;
	}
	private ActionListener addOperationAction = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			Operation newOperation = new Operation();
			newOperation.setName("");
			newOperation.setDescription("");
			newOperation.setParameters(new Vector<Var>());
			newOperation.setReturnData(new Var());
			newOperation.setVisibility(Operation.Visibility.PUBLIC);
			operations.add(newOperation);
			parameters.add("");
			if(operations.size()*16 > 150){
				table.setPreferredSize(new Dimension(250, operations.size()*16));
			}
			((AbstractTableModel)tableModel).fireTableChanged(null);
		}
	};
	
	private ActionListener deleteOperationAction = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			table.editingStopped(null);
			int indexOfSelected = table.getSelectedRow();
			operations.remove(indexOfSelected);
			parameters.remove(indexOfSelected);
			((AbstractTableModel)tableModel).fireTableChanged(null);
		}
	};
	
	@Override
	protected void processCancel() {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected boolean processOK() {
		table.editingStopped(null);
		boolean missingValues = false;
		for(int i = 0; i < operations.size(); i++){
			String name = operations.get(i).getName().replaceAll(" ", "");
			missingValues = (name.equals("")) || missingValues;
		}
		if(missingValues){
			JOptionPane.showMessageDialog(parent, "There are missing attribute names, please fill in or remove these elements!");
			return false;
		}else{
			//check the operator attributes
			for(int i = 0; i < parameters.size(); i++){
				if(!parameters.get(i).trim().equals("")){
					Vector<Var> vars = parseParameters(parameters.get(i));
					if(vars == null){
						return false;
					}
				}
			}
			//set the attributes
			for(int i = 0; i < parameters.size(); i++){
				if(!parameters.get(i).trim().equals("")){
					Vector<Var> vars = parseParameters(parameters.get(i));
					operations.get(i).setParameters(vars);
				}
			}
			return true;
		}
		
	}
	
	public Vector<Operation> getOperations(){
		return operations;
	}
	
	private ActionListener addNewRowAction = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			
		}
	};
	
	private class ClassOperationsTableColumns extends DefaultTableColumnModel{
		private TableColumn[] tempTableColumns = {
			new TableColumn(0, 50),
			new TableColumn(1, 50),
			new TableColumn(2, 50),
			new TableColumn(3, 50),
			new TableColumn(4, 200),
			new TableColumn(5, 50),
		};
		
		public ClassOperationsTableColumns(){
			tempTableColumns[0].setHeaderValue("Visibility");
			tempTableColumns[1].setHeaderValue("Return Type");
			tempTableColumns[2].setHeaderValue("Type Modifier");
			tempTableColumns[3].setHeaderValue("Name");
			tempTableColumns[4].setHeaderValue("Parameters");
			tempTableColumns[5].setHeaderValue("Description");
			for(int i= 0; i < 6; i++){
				tableColumns.add(tempTableColumns[i]);
			}
		}
		public int getColumnCount(){
			return tempTableColumns.length;
		}
	}
}
